use crate::app_error::*;
use crate::models::auth::*;
use crate::models::metainfo::*;
use crate::AppState;
use crate::{models, utils};
use anyhow::Result;
use axum::{extract::State, response::IntoResponse, routing::post, Router};
use chrono::Utc;
use std::sync::Arc;
use tower_http::trace::TraceLayer;
use tracing::{debug, error};

pub fn routes(state: Arc<AppState>) -> Router {
    Router::new()
        .route("/auth", post(auth))
        .layer(TraceLayer::new_for_http())
        .with_state(state)
}

// 用户登录
pub async fn auth(
    State(app_state): State<Arc<AppState>>,
    AppJson(payload): AppJson<AuthPayload>,
) -> Result<impl IntoResponse, AuthError> {
    // tracing::info!("login: {:?}", payload);

    if payload.username.is_empty() || payload.password.is_empty() {
        return Err(AuthError::MissingCredentials);
    }

    let user: crate::models::User = app_state
        .pg_dao
        .users_dao
        .get_user_by_username(&payload.username)
        .await
        .map_err(|e| {
            error!("get user error: {}", e);
            AuthError::InternalServerError
        })?
        .ok_or(AuthError::WrongCredentials)?;

    utils::verify_password(&payload.password, &user.password_hash)
        .map_err(|e| AuthError::WrongCredentials)?;

    debug!("user:{} verify password ok", payload.username);
    let role = models::Role::from_str(&user.role).ok_or(AuthError::InternalServerError)?;
    let claims = Claims {
        user_id: user.user_id,
        exp: Utc::now().timestamp() + 60 * 60 * 24, // 1 day
        role,
    };

    let token = create_token(claims)?;
    Ok(AppJson(SuccessResponse {
        code: 200,
        message: "ok".to_string(),
        data: AuthResBody::new(token),
    }))
}
